﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DotSpatial.Data;
using System.IO;
using DotSpatial.Projections;
using DotSpatial.Topology;
using DotSpatial.Controls;
using GeostatisticalTool.Classes;

namespace GeostatisticalTool.Forms
{
    public partial class DeterministicMethods : System.Windows.Forms.Form
    {
        private Map map;
        private ConfigurationMethod env;
        private IInterpolator inter;
        private CrossValidationCheck crossValidation;
       // private Extent ext;
        public Map Map
        {
            get { return map; }
            set { map = value; }
        }
        public DeterministicMethods()
        {
            InitializeComponent();
        }


        private void DeterministicMethods_Load(object sender, EventArgs e)
        {
            uxTypeOfMethod2.SelectedIndex = 0;
            uxNextPrevious.SetTab(uxPages);

            uxNextPrevious.SetTab(uxPages);
            env = new ConfigurationMethod(
            this.map,
            uxTypeOfMethod2,
            uxLayer,
            uxField
             );

            uxOutputRaster1.Path = env.PathFolder;
            uxOutputRaster1.NameOutput = env.Layer + "_" + uxTypeOfMethod2.Text;

            uxNextPrevious.SelectedNext += new EventHandler(uxNextPrevious_SelectedNext);
            uxNextPrevious.SelectedPrevious += new EventHandler(uxNextPrevious_SelectedPrevious);
            uxNextPrevious.uxClose.Click += new EventHandler(uxClose_Click);

        }

       

        private void uxNextPrevious_SelectedNext(object sender, EventArgs e)
        {

            if (uxPages.SelectedIndex == 0)
            {

                uxPages.TabPages[0].Enabled = false;
                uxPages.TabPages[1].Enabled = true;
                uxPages.SelectedIndex = 1;
                StartInterpolation();
                return;

              

            }
            if (uxPages.SelectedIndex == 1)
            {

                CreateCrossValidation();
          
                return;
            }
          

        }

        private void uxNextPrevious_SelectedPrevious(object sender, EventArgs e)
        {
            if (uxPages.SelectedIndex == 1)
            {
                uxPages.TabPages[1].Enabled = false;
                uxPages.TabPages[0].Enabled = true;
                uxPages.SelectedIndex = 0;
                                return;
            }


            if (uxPages.SelectedIndex == 2)
            {

                return;

            }

        }
        private void StartInterpolation()
        {
            /*Inverse Distance Weight (IDW)
            Radial Basis Functions
            Local Polynomial Interpolation
            Global Polynomial Interpolation
             */
            this.uxOperationsMap1.SetProjection(env.OriginalData.Projection);
            if (env.Method == "Inverse Distance Weighted (IDW)")
            {
                if (!env.Load(2))
                    return;
            }
            else
            {
                if (!env.Load(7))
                    return;
            }
            
            env.UpdateWorkField(0);

            uxOutputRaster1.Path = env.PathFolder;
            uxOutputRaster1.NameOutput = env.Layer + "_" + uxTypeOfMethod2.Text;


            if (env.Method == "Inverse Distance Weighted (IDW)")
            {
                 inter = new IDW(env.Data, 6);
                uxParameterDeterministic1.SetMethod("IDW");
                ParameterInterpolator par = new ParameterInterpolator();
                par.Value = 2;
                uxParameterDeterministic1.SetParameter(par);
                inter.SetParameters(uxParameterDeterministic1.GetParameter());

                uxSearchNeighborhoodControl1.Visible = true;
               // DataSourceInterpolators datasource= idw.;

                ConfigSearchControl(inter);
                ConfigureOperationParametersInterpoltors();
                InterpolatePrevious();

            }


            if (env.Method == "Local Polynomial Interpolation")
            {
                inter = new LocalTrend(env.Data, 6,1);
                uxParameterDeterministic1.SetMethod("local");
                uxSearchNeighborhoodControl1.Visible = true;
                ParameterInterpolator par = new ParameterInterpolator();
                par.Index = 1;
                uxParameterDeterministic1.SetParameter(par);
                inter.SetParameters(uxParameterDeterministic1.GetParameter());

                uxSearchNeighborhoodControl1.Visible = true;
                // DataSourceInterpolators datasource= idw.;

                ConfigSearchControl(inter);
                ConfigureOperationParametersInterpoltors();
                InterpolatePrevious();

            }

            if (env.Method == "Global Polynomial Interpolation")
            {
                 inter = new Trend(env.Data, 6,1);
                uxParameterDeterministic1.SetMethod("Global");
                uxSearchNeighborhoodControl1.Visible = false;
                ParameterInterpolator par = new ParameterInterpolator();
                par.Index = 1;
                uxParameterDeterministic1.SetParameter(par);
                inter.SetParameters(uxParameterDeterministic1.GetParameter());

                // DataSourceInterpolators datasource= idw.;

                ConfigureOperationParametersInterpoltors();
                InterpolatePrevious();
            
            }


            uxOutputInterpolation.DataSource = env.Data.DataTable;

        }

        private void ConfigureOperationParametersInterpoltors()
        {
            uxPredictedValue1.ChangedCoordinate += new EventHandler(uxPredictedValue1_ChangedCoordinate);
            this.uxOperationsMap1.ChangedCoordinate += new EventHandler(uxOperationsMap1_ChangedCoordinate);
            uxParameterDeterministic1.ChangedParameters += new EventHandler(uxParameterDeterministic1_ChangedParameters);
            uxParameterDeterministic1.EnableApply(false);
        }

        private void ConfigSearchControl(IInterpolator inter)
        {
            uxSearchNeighborhoodControl1.MajorR = inter.GetSearch().InitialDistanceSearch;
            uxSearchNeighborhoodControl1.MinorR = inter.GetSearch().InitialDistanceSearch;
            uxSearchNeighborhoodControl1.Type = 1;
            uxSearchNeighborhoodControl1.Az = 0;
            uxSearchNeighborhoodControl1.SetSearch(inter.GetSearch());
            uxSearchNeighborhoodControl1.ChangedParameters += new EventHandler(uxSearchNeighborhoodControl1_ChangedParameters);
            uxSearchNeighborhoodControl1.EnableApply(false);
        }

        private void InterpolatePrevious()
        {
            InsertSurfaceInMap();
            this.uxOperationsMap1.SetPointLayer(env.Data);
            this.uxPredictedValue1.SetCoor(inter, (env.Data.Extent.MinX + env.Data.Extent.Width / 2), (env.Data.Extent.MinY + env.Data.Extent.Height / 2),0);
            this.uxPredictedValue1.EnableApply(false);
        }

        private void InsertSurfaceInMap()
        {
            double cell = env.Data.Extent.Width / 30;
           

            IRaster newgrid = inter.Surface(env.Data.Extent, cell, env.Data.Projection, -32768, Path.GetTempPath() + "\\inter.bgd");////********************change path
            this.uxOperationsMap1.ValuesMinMax = new double[2] { newgrid.Minimum-0.001, newgrid.Maximum };
            this.uxOperationsMap1.SetSurface(newgrid);
        }

        private void uxSearchNeighborhoodControl1_ChangedParameters(object sender, EventArgs e)
        {

            uxPredictedValue1.Recalculate();
            RecalculatePoint();
            InsertSurfaceInMap();

        }

        private void uxParameterDeterministic1_ChangedParameters(object sender, EventArgs e)
        {
            inter.SetParameters(uxParameterDeterministic1.GetParameter());
            uxPredictedValue1.Recalculate();
            RecalculatePoint();
            InsertSurfaceInMap();

        }


        private void uxPredictedValue1_ChangedCoordinate(object sender, EventArgs e)
        {
            RecalculatePoint();
        }

        private void RecalculatePoint()
        {
            if (inter.GetMethodName() == "Trend")
                return;

            List<IGeometry> data = new List<IGeometry>();
            SearchData search =inter.GetSearch();


            foreach (Kpoint p in search.SelectedPoints)
                data.Add(new DotSpatial.Topology.Point(p.X, p.Y, p.Z));

            this.uxOperationsMap1.AddGeometries("point", data);
            if (uxSearchNeighborhoodControl1.Type == 1)
                this.uxOperationsMap1.AddGeometries("polygon", search.ZoneSelected(env.Data, uxPredictedValue1.X, uxPredictedValue1.Y, uxPredictedValue1.Z)[0]);

            if (uxSearchNeighborhoodControl1.Type == 4)
            {
                this.uxOperationsMap1.AddGeometries("polygon", search.ZoneSelected(env.Data, uxPredictedValue1.X, uxPredictedValue1.Y, uxPredictedValue1.Z)[0]);
                this.uxOperationsMap1.AddGeometries("line", search.ZoneSelected(env.Data, uxPredictedValue1.X, uxPredictedValue1.Y, uxPredictedValue1.Z)[1]);
            }

            this.uxOperationsMap1.SetCoordinates(uxPredictedValue1.X, uxPredictedValue1.Y);
        }

        private void uxOperationsMap1_ChangedCoordinate(object sender, EventArgs e)
        {
            uxPredictedValue1.SetCoor(inter, this.uxOperationsMap1.X, this.uxOperationsMap1.Y, this.uxOperationsMap1.Z);
        }

        private void CreateCrossValidation()
        {
            double[] result = inter.CrossValidation();


            uxOutputRaster1.Map = this.map;
            uxOutputRaster1.Ext = env.Data.Extent;
            uxOutputRaster1.NameLayer = env.Layer;
            uxOutputRaster1.Name = "Surface";
            uxOutputRaster1.Path = Path.GetTempPath();
            uxOutputRaster1.Pixel = Convert.ToString(env.Data.Extent.Width / 50);
            // uxPathFile.Text = Path.GetTempPath();
            // uxPixelSize.Text = Convert.ToString(env.Data.Extent.Width / 50);
            uxOutputRaster1.uxCreate.Click += new EventHandler(uxCreate_Click);


            //result[0] = Math.Sqrt(SSerror / numberUsed); //RMS

            uxErrorResult.Text = string.Format(
@"   Statistical Error

            Mean prediction errors           :{1}
            RMS prediction errors              :{0}
            ", result[0], result[1]);


            //ListOFValues  ->  true value, predicted value, error, std error /////////////////
            //"Measured","Trans","Trend","Predicted","Error","StdError"       /////////////////
            UpdataCrossValidationRegression("Measured", "Predicted", "Cross Validation", 0, 1);



            uxPages.TabPages[1].Enabled = false;
            uxPages.TabPages[2].Enabled = true;
            uxPages.SelectedIndex = 2;
        }

        private void UpdataCrossValidationRegression(string fieldX, string fieldY, string title, int indexListOfValuesX, int indexListOfValuesY)
        {

            //ListOFValues  ->  true value, predicted value, error, std error /////////////////
            //"Measured","Trans","Trend","Predicted","Error","StdError"       /////////////////
            CalculateErrorsCrossValidation cal = new CalculateErrorsCrossValidation(env.Data, env.CheckData);
            List<double[]> listOfValues = cal.UpdatePredictedTableDeterministics(inter, env.Trend, env.Transformation);
            double[] regression = cal.CrossValidationRegression(fieldX, fieldY);
            double MaxZValue = inter.GetMaxValuesZ()[1];
            crossValidation = new CrossValidationCheck(zedGraphControl2, listOfValues);
            uxRegression.Text = string.Format(
                fieldX + @" = {1} + {0}*" + fieldY + " r= {2}", Math.Round(regression[0],3), Math.Round(regression[1],3), Math.Round(regression[2],3));

            crossValidation.DrawPoints(fieldX, fieldY, title, indexListOfValuesX, indexListOfValuesY);
            if (title == "Cross Validation")
                crossValidation.GuideLine(MaxZValue);

            crossValidation.RegressionLine(MaxZValue, regression[0], regression[1]);
        }

        private void uxPredicted_CheckedChanged(object sender, EventArgs e)
        {
            //ListOFValues  ->  true value, predicted value, error, std error /////////////////
            //"Measured","Trans","Trend","Predicted","Error","StdError"       /////////////////
            if (uxPredicted.Checked)
                UpdataCrossValidationRegression("Measured", "Predicted", "Cross Validation", 0, 1);
        }

        private void uxError_CheckedChanged(object sender, EventArgs e)
        {
            //ListOFValues  ->  true value, predicted value, error, std error /////////////////
            //"Measured","Trans","Trend","Predicted","Error","StdError"       /////////////////
            if (uxError.Checked)
                UpdataCrossValidationRegression("Measured", "Error", "Error", 0, 2);
        }



        private void uxCreate_Click(object sender, EventArgs e)
        {

            if (Validator.IsDouble(uxOutputRaster1.Pixel) && uxOutputRaster1.Path != "")
            {
                if (uxOutputRaster1.Clip == null)
                {
                    IRaster newgrid = inter.Surface(uxOutputRaster1.Ext, Convert.ToDouble(uxOutputRaster1.Pixel), env.Data.Projection, -32768, @uxOutputRaster1.Path + uxOutputRaster1.NameOutput + ".bgd");////********************change path.bgd
                    map.Layers.Add(newgrid);
                

                }
                else
                {
                    Clip clip = uxOutputRaster1.Clip;
                    IRaster mask = clip.GetClip(uxOutputRaster1.Ext, Convert.ToDouble(uxOutputRaster1.Pixel), @uxOutputRaster1.Path + "mask.bgd");
                    IRaster newgrid = inter.Surface(mask,uxOutputRaster1.Ext, Convert.ToDouble(uxOutputRaster1.Pixel), env.Data.Projection, -32768, @uxOutputRaster1.Path + uxOutputRaster1.NameOutput + ".bgd");////********************change path.bgd
                    map.Layers.Add(newgrid);
                
                }
                  
            }
        }
        private void uxClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void uxTypeOfMethod2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (uxLayer.Text != null)
            {
                uxOutputRaster1.NameOutput = uxLayer.Text + "_" + uxTypeOfMethod2.Text;
            }
            else
            {
                uxOutputRaster1.NameOutput = uxTypeOfMethod2.Text;
            }
        }
    }
}
